package com.ruijie.acl.service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.util.Assert;

import com.ruijie.acl.AccessGroup;
import com.ruijie.acl.Ace;
import com.ruijie.acl.AclDevice;
import com.ruijie.acl.AclDeviceTimeRange;
import com.ruijie.acl.TimeInfo;
import com.ruijie.acl.TimeRange;
import com.ruijie.acl.task.config.TaskConfigAclDevice;
import com.ruijie.acl.task.model.TimeRangeInfo;
import com.ruijie.acl.utils.AclConfigUtil;
import com.ruijie.acl.utils.AclUtil;
import com.ruijie.batch.plan.PlanParameters;
import com.ruijie.emp.device.Device;
import com.ruijie.foundation.dao.support.Page;
import com.ruijie.foundation.exception.BusinessException;
import com.ruijie.foundation.utils.StringUtils;

/**
 * <p>
 * Title: ACL时间段接口实现类
 * 
 * </p>
 * <p>
 * Description: 为ACL模板模块提供逻辑处理，以及数据库的操作。

 * 
 * </p>
 * <p>
 * Copyright: Copyright (c) 2008
 * </p>
 * <p>
 * Company: Ruijie Co., Ltd.
 * </p>
 * <p>
 * Create Time:
 * </p>
 * <p>
 * Update Time:
 * </p>
 * <p>
 * Updater:
 * </p>
 * <p>
 * Update Comments:
 * </p>
 * 
 * @author ASAI
 */

public class TimeRangeServiceImpl extends
		AclHibernateEntityExtendDao<TimeRange> implements TimeRangeService {
	
	private AclPlanParametersService parametersService;
	
	private TimeInfoService timeInfoService;
	
	private AceService aceService;
	
	private TaskConfigAclDevice taskConfigAclDevice;
	
	private DeviceTimeRangeService deviceTimeRangeService;
	
	private AclDeviceService aclDeviceService;
	
	public TimeInfoService getTimeInfoService() {
		return timeInfoService;
	}

	public void setTimeInfoService(TimeInfoService timeInfoService) {
		this.timeInfoService = timeInfoService;
	}

	/**
	 * 分页查询时间段

	 * 
	 * @param timeRange
	 *            时间段

	 * @param pageNo
	 *            页数
	 * @param pageSize
	 *            每面显示的记录数
	 * @return 时间段

	 */
	public Page pageQueryByTimeRange(TimeRange timeRange, int pageNo,
			int pageSize) {
		Assert.notNull(timeRange);
		Criteria criteria = createCriteria(TimeRange.class);
		if (!StringUtils.isNullOrEmpty(timeRange.getName())) {
			criteria.add(Restrictions.like("name", timeRange.getName(),
					MatchMode.ANYWHERE));
		}
		//criteria.add(Restrictions.eq("deleteFlg", false));
		// 且不是导入的设备组。

		criteria.add(Restrictions.isNull("aclDevice"));
		return pagedQuery(criteria, pageNo, pageSize);
	}

	/**
	 * 时间段名称重复验证

	 * 
	 * @param name
	 *            时间段名称

	 * @return true or false
	 */
	public boolean isExistTimeRangeName(String name, Long id) {
		Criteria criteria = createCriteria(TimeRange.class);
		criteria.add(Restrictions.eq("name", name));
		//.add(Restrictions.eq("deleteFlg", false));
		// 如果ID号 != null ,则表示为修改，如果ID号 == null ，则为添加

		if (id != null) {
			Criterion idCriterion = Restrictions.not(Restrictions.eq("id", id));
			criteria.add(idCriterion);
		}
		int totalCount = (Integer) criteria.setProjection(
				Projections.rowCount()).uniqueResult();

		// 如果都没有被使用,返回False
		if (totalCount == 0) {
			return false;
		} else {
			return true;
		}
	}

	/**
	 * 根据名称取得ACL时间段信息

	 * 
	 * @param name
	 *            ACl时间段名称

	 * 
	 * @return List 时间段信息

	 */
	@SuppressWarnings("unchecked")
	public List<TimeRange> getByName(String name) {
		Assert.notNull(name);
		Criteria criteria = createCriteria(TimeRange.class);
		
		criteria.add(Restrictions.eq("name", name));
		//.add(Restrictions.eq("deleteFlg", false));
		List<TimeRange> list = criteria.list();
		return list;
	}
	
	/**
	 * 取得系统ACL时间段信息
	 * 
	 * @param name
	 *            ACl时间段名称
	 * 
	 * @return List 时间段信息
	 */
	@SuppressWarnings("unchecked")
	public List<TimeRange> getWithoutAclDevice() {
		Criteria criteria = createCriteria(TimeRange.class);
		criteria.add(Restrictions.isNull("aclDevice"));
		List<TimeRange> list = criteria.list();
		return list;
	}
	
	/**
	 * 根据名称取得有ACL设备的ACL时间段信息

	 * 
	 * @param name
	 *            ACL时间段名称

	 * @param aclDevice
	 *            ACL设备
	 * 
	 * @return List 时间段信息

	 */
	@SuppressWarnings("unchecked")
	public TimeRange getByNameWithAclDevice(String name, AclDevice aclDevice) {
		Assert.notNull(aclDevice);
		if (name == null){
			return null;
		}
		Criteria criteria = createCriteria(TimeRange.class);
		criteria.add(Restrictions.eq("name", name));
		criteria.add(Restrictions.eq("aclDevice", aclDevice));
		List<TimeRange> list = criteria.list();
		TimeRange timeRangeDevice = null;
		if (list != null && list.size() > 0){
			timeRangeDevice = list.get(0);
		}
		return timeRangeDevice;
	}
	/**
	 * 根据名称取得无ACL设备的ACL时间段信息

	 * 
	 * @param name
	 *            ACl时间段名称

	 * 
	 * @return List 时间段信息

	 */
	@SuppressWarnings("unchecked")
	public TimeRange getByNameWithoutAclDevice(String name) {
		if (name == null){
			return null;
		}
		List<TimeRange> list = getByName(name);
		TimeRange timeRangeSystem = null;
		if (list != null && list.size() > 0){
			for (TimeRange timeRange : list){
				if (timeRange.getAclDevice() == null){
					timeRangeSystem = timeRange;
					
				}
			}
		}
		return timeRangeSystem;
	}
	//删除时间列表
	private void removeTimeInfoByTimeRange(TimeRange entity) {
		String hql = "delete from TimeInfo where timeRange = ?"; 
		createQuery(hql, entity).executeUpdate();
	}
	
	//删除规则
//	private void removeAceByTimeRange(TimeRange entity) {
//		String hql = "update Ace set timeRange=null,timeRangeName=null where timeRange = ?";//"delete from Ace where timeRange = ?";
//		createQuery(hql, entity).executeUpdate();
//	}
	
	//删除关联设备
	private void removeAclDeviceByTimeRange(TimeRange entity) {
		String hql = "delete from AclDeviceTimeRange where timeRange = ?";
		createQuery(hql, entity).executeUpdate();
	}
	/**
	 * 去除模板所使用的ACL规则中含有的指定时间段
	 * @param entity 时间段
	 */
	private void removeTemplateAceTimeRange(TimeRange entity){
		//必须为系统时间段,设备时间段不处理
		if (entity.getAclDevice() == null){
			String hql = "update Ace set timeRange=null,timeRangeName=null where template is not null and (timeRange=? or timeRangeName=?)";
			createQuery(hql, entity, entity.getName()).executeUpdate();
		}
	}
	/**
	 * 删除与指定时间段对应的设备时间段
	 * @param entity 时间段
	 */
	public void removeWithAclDevice(TimeRange entity){
		//系统时间段时,删除所有其对应的设备时间段信息
		if (entity.getAclDevice() == null){
			//删除关联的TimeInfo
			String hql = "delete from TimeInfo where timeRange.id in (select tr.id from TimeRange tr where tr.name = ? and tr.aclDevice is not null)";
			createQuery(hql, entity.getName()).executeUpdate();
			//删除ACL设备和时间段的关联(通常情况下不可能存在关联,保险起见)
			hql = "delete from AclDeviceTimeRange where timeRange.id in (select tr.id from TimeRange tr where tr.name = ? and tr.aclDevice is not null)";
			createQuery(hql, entity.getName()).executeUpdate();
			//更新设备ACE,去除时间段信息,包括时间段和时间段名称
			hql = "update Ace set timeRange=null, timeRangeName=null " 
				+ " where (timeRange=? or timeRangeName=?) " 
				+ " 		and accessGroup is not null and accessGroup in ("
				+ " 			select ag.id from AccessGroup ag " 
				+ " 			where ag.aclDevice is not null"
				+ "			)";
			createQuery(hql, entity, entity.getName()).executeUpdate();
			//删除设备时间段
			hql = "delete from TimeRange where name = ? and aclDevice is not null";
			createQuery(hql, entity.getName()).executeUpdate();
		}else{ //设备时间段时,清空其对应的ACE中的引用
			String hql = "update Ace set timeRange=null " 
				+ " where (timeRange=? or timeRangeName=?) " 
				+ " 		and accessGroup is not null and accessGroup in ("
				+ " 			select ag.id from AccessGroup ag " 
				+ " 			where ag.aclDevice=?"
				+ "			)";
			createQuery(hql, entity, entity.getName(),entity.getAclDevice()).executeUpdate();
		}
	}
	@Override
	public void remove(TimeRange entity) {
		if(!isExitesAce(entity)){
			removeWithAclDevice(entity);
			removeTimeInfoByTimeRange(entity);
			removeAclDeviceByTimeRange(entity);
			removeTemplateAceTimeRange(entity);
			super.remove(entity);
		}else{
			throw new BusinessException("acl_time_delete_use_error", entity.getName());
		}
	}
	
	/**
	 * 时间段是否关联规则

	 * @param entity
	 * @return
	 */
	public boolean isExitesAce(TimeRange entity){
		/*
		Criteria accessGroupCriteria = createCriteria(AccessGroup.class);
		accessGroupCriteria.add(Restrictions.isNull("aclDevice"));
		List<AccessGroup> accessGroupList = accessGroupCriteria.list();
		Criteria criteria = createCriteria(Ace.class);
		criteria.add(Restrictions.eq("timeRange", entity));
		criteria.add(Restrictions.isNotNull("accessGroup"));
		if (accessGroupList != null && accessGroupList.size() > 0){
			criteria.add(Restrictions.in("accessGroup", accessGroupList));
		}
		int count = (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();
		*/
		String hql = "select count(*) from Ace ace,AccessGroup ag where ace.timeRange=? and (ace.accessGroup=ag and ag.aclDevice is null or ace.template is not null)";
		Long count = (Long)(this.createQuery(hql, entity).uniqueResult());
		
		return count != null && count.intValue() > 0;
	}
	
	
	/**
	 * 时间段是否关联规则

	 * @param entity
	 * @return
	 */
	public boolean isExitesAce(TimeRange entity,AclDevice aclDevice){
		List<Object> paramList = new ArrayList<Object>();
		String hql ="select count(*) from Ace ace,AccessGroup ag where ace.accessGroup=ag and ace.timeRange.name=? and ag.aclDevice = ? ";
		paramList.add(entity.getName());
		paramList.add(aclDevice);
		Long count = (Long)(this.createQuery(hql, paramList.toArray()).uniqueResult());		
		return count != null && count.intValue() > 0;
	}
	
	

	
	/**
	 * 时间段详细界面的单设备部署

	 * @param id
	 * @param device
	 */
	public void reConfig(TimeRange timeRange,Device device,String dealFlag){		
			PlanParameters parameters = new PlanParameters();
			Set<TimeInfo> timeInfoSet = new HashSet<TimeInfo>(timeInfoService.getByTimeRange(timeRange));
			timeRange.setTimeInfos(timeInfoSet);
			//List<AccessGroup> accessGroupList = getAccessGroupList(timeRange);	
			/*存入timeRangeInfoList*/
			List<TimeRangeInfo> timeRangeInfoList = new ArrayList<TimeRangeInfo>();
			timeRangeInfoList.add(AclConfigUtil.timeRange2TimeRangeInfo(timeRange));
			parameters.putParameter("timerangeInfoList", timeRangeInfoList);
			
			/*存入accessGroupInfoList*/
			//List<AccessGroupInfo> accessGroupInfoList = aceService.accessGroup2AccessGroupInfo(accessGroupList);
			//parameters.putParameter("accessGroupInfoList", accessGroupInfoList);
			
			/*存入DealType*/
			parameters.putParameter("dealFlag",dealFlag);
			taskConfigAclDevice.processItem(device, parameters);
			AclDevice aclDevice = aclDeviceService.getByDevice(device);
			updateChangeFlag(timeRange, aclDevice);
			if (!"DeleteTimeRange".equals(dealFlag)){
				//创建新的时间段(设备)信息
				this.saveSameWithAclDevice(timeRange, aclDevice, null);
			}
	}
	
	/**
	 * 判断时间段是否与设备关联
	 * @param entity
	 * @return
	 */
	public boolean isRelated2Device(TimeRange entity){
		Criteria criteriaDeviceTimeRange = createCriteria(AclDeviceTimeRange.class);
		criteriaDeviceTimeRange.add(Restrictions.eq("timeRange", entity));
		int result = (Integer) criteriaDeviceTimeRange.setProjection(Projections.rowCount()).uniqueResult();
		return result>0;
	}
	
	/**
	 * 通过时间段获得device
	 * @param entity 时间段

	 * @return device 
	 */
	@SuppressWarnings("unchecked")
	public List<Device> getDevices(TimeRange entity){
		Criteria criteria = createCriteria(AclDeviceTimeRange.class);
		criteria.add(Restrictions.eq("timeRange", entity));
		List<AclDeviceTimeRange> list = criteria.list();
		List<Device> deviceList = new ArrayList<Device>();
		for(AclDeviceTimeRange deviceTimeRange:list){
			Device device = deviceTimeRange.getAclDevice().getDevice();
			deviceList.add(device);
		}
		return deviceList;
	}
	
	/**
	 * 通过时间段获得AccessGroup的ids或name
	 * @param entity 时间段

	 * @param isDelete 是否删除
	 * @return AccessGroup的ids或name
	 */
	@SuppressWarnings("unchecked")
	public String getAccessGroups(TimeRange entity,boolean isDelete){
		Criteria criteria = createCriteria(Ace.class);
		criteria.add(Restrictions.eq("timeRange", entity));
		criteria.add(Restrictions.isNotNull("accessGroup"));
		List<Ace> actList = criteria.list();
		HashSet<AccessGroup> set = new HashSet<AccessGroup>();
		String str="";
		for(Ace ace:actList){
			AccessGroup group = ace.getAccessGroup();
			set.add(group);
		}
		if(isDelete){
			for(AccessGroup accessGroup:set){
				if(str.equals("")){
					str = AclUtil.escapeSpecialString(accessGroup.getName());
				}else{
					str += ","+AclUtil.escapeSpecialString(accessGroup.getName());
				}
			}
		}else{
			for(AccessGroup accessGroup:set){
				if(str.equals("")){
					str = String.valueOf(accessGroup.getId());
				}else{
					str += ","+accessGroup.getId();
				}
			}
		}
		return str;
	}
	
	/**
	 * 通过时间段获得AccessGroup
	 * @param entity 时间段

	 * @return List<AccessGroup>
	 */
	@SuppressWarnings("unchecked")
	public List<AccessGroup> getAccessGroupList(TimeRange entity){
		Criteria criteria = createCriteria(Ace.class);
		criteria.add(Restrictions.eq("timeRange", entity));
		List<Ace> actList = criteria.list();
		List<AccessGroup> accessGroupList = new ArrayList<AccessGroup>();
		HashSet<AccessGroup> set = new HashSet<AccessGroup>();
		for(Ace ace:actList){
			AccessGroup group = ace.getAccessGroup();
			set.add(group);
		}
		accessGroupList.addAll(set);
		return accessGroupList;
	}
	
	@Override
	public void remove(Serializable[] ids){
		String names = "";
		for(Serializable id:ids){
			TimeRange timeRange = super.get(id);
			try {
				this.remove(timeRange);
			} catch (BusinessException e) {
				names += "," + timeRange.getName();
			}
		}
		if (names.length() > 0){
        	throw new BusinessException("acl_time_delete_use_error", names.substring(1));
        }
	}
	
	/**
	 * <p>根据ID字符串取得时间段信息</p>
	 * <p>ID字符串使用逗号(,)分隔</p> 
	 * @return 时间段信息列表

	 */
	public List<TimeRange> findByIds(String ids){
		Assert.hasText(ids);
		String[] arrIds = ids.split(",");
		List<Long> idList = new ArrayList<Long>();
		for(String id : arrIds){
			if (id.trim().length() > 0){
				idList.add(Long.parseLong(id));
			}
		}
		return this.findByIds(idList.toArray(new Long[idList.size()]));
	}
	
	/**
	 * <p>根据ID数组取得时间段信息</p>
	 * @return 时间段信息列表

	 */
	@SuppressWarnings("unchecked")
	public List<TimeRange> findByIds(Long[] ids){
		Assert.notNull(ids);
		Criteria criteria = createCriteria(TimeRange.class);
		criteria.add(Restrictions.in("id", ids));
		return criteria.list();
	}

	/**
	 * 根据ACL组获取相关联的时间段
	 * @param accessGroup
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<TimeRange> findByAccessGroup(AccessGroup accessGroup) {
		Assert.notNull(accessGroup);
		String hql="from TimeRange t,Ace ace where t.aclDevice=null and ace.timeRange=t and ace.accessGroup=?";
		List list=createQuery(hql, accessGroup).list();
		List<TimeRange> result=new ArrayList<TimeRange>();
		for(Object obj:list){
			Object[] temp=(Object[])obj;
			TimeRange tr=(TimeRange)temp[0];
			if(!result.contains(tr)){
				result.add(tr);
			}
		}
		return result;
	}
	
	/**
	 * 根据ACL组列表获取相关联的时间段列表
	 * @param accessGroups ACL组列表

	 * @return 时间段列表

	 */
	@SuppressWarnings("unchecked")
	public List<TimeRange> findByAccessGroup(List<AccessGroup> accessGroups){
		Assert.notEmpty(accessGroups);
		String accessGroupIds = "";
		for(AccessGroup accessGroup :accessGroups){
			accessGroupIds += ","+accessGroup.getId().toString();
		}
		if(accessGroupIds.length()>0){
			accessGroupIds = accessGroupIds.substring(1);
		}
		String hql="from TimeRange t,Ace ace where ace.timeRange=t and ace.accessGroup in (" + accessGroupIds+ ")";
		List list=createQuery(hql).list();
		List<TimeRange> resultList=new ArrayList<TimeRange>();
		for(Object obj:list){
			Object[] temp=(Object[])obj;
			TimeRange tr=(TimeRange)temp[0];
			if(!resultList.contains(tr)){
				resultList.add(tr);
			}
		}
		return resultList;
	}
	
	public AclPlanParametersService getParametersService() {
		return parametersService;
	}

	public void setParametersService(AclPlanParametersService parametersService) {
		this.parametersService = parametersService;
	}

	public AceService getAceService() {
		return aceService;
	}

	public void setAceService(AceService aceService) {
		this.aceService = aceService;
	}

	public TaskConfigAclDevice getTaskConfigAclDevice() {
		return taskConfigAclDevice;
	}

	public void setTaskConfigAclDevice(TaskConfigAclDevice taskConfigAclDevice) {
		this.taskConfigAclDevice = taskConfigAclDevice;
	}
	/**
	 * 删除与指定时间段同名且包含ACL设备的记录

	 * @param entity 时间段

	 */
	public void updateChangeFlag(TimeRange entity, AclDevice aclDevice){
		//修改多对多关系的修改标志位
		AclDeviceTimeRange aclDeviceTimeRange =  deviceTimeRangeService.getByAclDeviceAndTimeRange(aclDevice, entity);
		if (aclDeviceTimeRange != null && aclDeviceTimeRange.getIsChanged()){
			aclDeviceTimeRange.setIsChanged(false);
			deviceTimeRangeService.update(aclDeviceTimeRange);
		}
		//判断更新时间段修改标志位
		if (entity.getIsChanged() && !deviceTimeRangeService.existByTimeRangeAndChanged(entity)){
			entity.setIsChanged(false);
			this.update(entity);
		}
	}

	public DeviceTimeRangeService getDeviceTimeRangeService() {
		return deviceTimeRangeService;
	}

	public void setDeviceTimeRangeService(
			DeviceTimeRangeService deviceTimeRangeService) {
		this.deviceTimeRangeService = deviceTimeRangeService;
	}
	
	/**
	 * 保存与指定时间段列表且包含指定设备对应的ACL设备的时间段
	 * @param entityList 时间段
	 * @param device 设备
	 */
	public void saveSameWithDevice(List<TimeRange> entityList, Device device){
		if (entityList != null && entityList.size() > 0){
			AclDevice aclDevice = aclDeviceService.getByDevice(device);
			if (aclDevice != null){
				for (TimeRange entity : entityList){
					saveSameWithAclDevice(entity, aclDevice, null);
				}
			}
		}
	}
	/**
	 * 保存与指定时间段相同信息且包含ACL设备的时间段
	 * @param entity 时间段
	 * @param aclDevice ACL设备
	 * @param timeInfoList TimeInfo列表
	 */
	public void saveSameWithAclDevice(TimeRange entity, AclDevice aclDevice, List<TimeInfo> timeInfoList){
		Assert.notNull(entity);
		Assert.notNull(aclDevice);
		//判断是否存在,不存在则新建
		TimeRange newEntity = this.getByNameWithAclDevice(entity.getName(),aclDevice);
		//删除原TimeInfo信息 
		if (newEntity != null){
			timeInfoService.deleteByTimeRange(newEntity);
		}
		newEntity = entity.clone(newEntity, aclDevice);
		this.save(newEntity);
		//保存新TimeInfo信息,但若为null保存源时间段的TimeInfo集

		if (timeInfoList == null){
			List<TimeInfo> tiList = timeInfoService.getByTimeRange(entity);
			if (tiList != null && tiList.size() > 0){
				for (TimeInfo timeInfo : tiList){
					TimeInfo tiEntity = timeInfo.clone(newEntity);
					timeInfoService.save(tiEntity);
				}
			}
		}else if (timeInfoList != null && timeInfoList.size() > 0){
			for (TimeInfo timeInfo : timeInfoList){
				TimeInfo tiEntity = timeInfo.clone(newEntity);
				timeInfoService.save(tiEntity);
			}
		}
	}

	public AclDeviceService getAclDeviceService() {
		return aclDeviceService;
	}

	public void setAclDeviceService(AclDeviceService aclDeviceService) {
		this.aclDeviceService = aclDeviceService;
	}
	/**
	 * 更新时间段的修改标志位
	 * @param list 时间段列表
	 */
	public void updateChangeFlag(List<TimeRange> list){
		if (list != null && list.size() > 0){
			for (TimeRange timeRange : list){
				updateChangeFlag(timeRange);
			}
		}
	}
	/**
	 * 更新时间段修改标志位
	 * @param entity 时间段
	 */
	public void updateChangeFlag(TimeRange entity){
		//判断更新时间段修改标志位
		if (entity.getIsChanged() && !deviceTimeRangeService.existByTimeRangeAndChanged(entity)){
			entity.setIsChanged(false);
			this.update(entity);
		}
	}
	/**
	 * 取得包含指定ACL设备的时间段列表
	 * @param aclDevice ACL设备
	 * @return 时间段列表
	 */
	@SuppressWarnings("unchecked")
	public List<TimeRange> getByAclDevice(AclDevice aclDevice){
		Assert.notNull(aclDevice);
		List<TimeRange> list = new ArrayList<TimeRange>();
		Criteria criteria = createCriteria(TimeRange.class);
		criteria.add(Restrictions.eq("aclDevice", aclDevice));
		list = (List<TimeRange>) criteria.list();
		return list;
	}
}
